use crate::error::*;
use log::info;
use serde::{Deserialize, Serialize};
use sqlx::{Arguments};
use sqlx_mysql::MySqlArguments;
use tracing_subscriber::fmt::format;
use std::{collections::HashMap, fmt::Display, iter, vec};
use tracing::{error,  warn};

pub trait ToSqlMaker {
    fn get_sql(&self) -> String;
    fn get_bind(&self) -> Option<MySqlArguments>;
    fn get_persistent(&self) -> bool {
        return self.get_bind().is_some();
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SqlMakerExpress {
    Str(String),
    Literal(String),
}

impl Display for SqlMakerExpress {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            SqlMakerExpress::Str(v) => write!(f, "{}", v),
            SqlMakerExpress::Literal(v) => write!(f, "{}", v),
        }
    }
}

macro_rules! convert_to_sql_maker_express_impl {
    ($($ty:ty),+) => ($(
        impl From<$ty> for $crate::db::query_statement::SqlMakerExpress {
            fn from(value: $ty) -> Self {
                $crate::db::query_statement::SqlMakerExpress::Str(format!("{}",value))
            }
        }
    )+)
}

convert_to_sql_maker_express_impl!(String, &str, &String);

impl SqlMakerExpress {
    pub fn is_literal(&self) -> bool {
        match self {
            SqlMakerExpress::Literal(_) => true,
            _ => false,
        }
    }

    pub fn is_str(&self) -> bool {
        !self.is_literal()
    }

    pub fn literal(self) -> Option<String> {
        match self {
            SqlMakerExpress::Literal(v) => Some(v),
            _ => None,
        }
    }

    pub fn str(self) -> Option<String> {
        match self {
            SqlMakerExpress::Literal(_) => None,
            SqlMakerExpress::Str(v) => Some(v),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SqlMakerBindValue {
    U8(u8),
    I8(i8),
    U16(u16),
    I16(i16),
    U32(u32),
    I32(i32),
    U64(u64),
    I64(i64),
    USIZE(usize),
    ISIZE(isize),
    Bool(bool),
    Str(String),
}

impl Display for SqlMakerBindValue {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            SqlMakerBindValue::U8(v) => write!(f, "{}", v),
            SqlMakerBindValue::I8(v) => write!(f, "{}", v),
            SqlMakerBindValue::U16(v) => write!(f, "{}", v),
            SqlMakerBindValue::I16(v) => write!(f, "{}", v),
            SqlMakerBindValue::U32(v) => write!(f, "{}", v),
            SqlMakerBindValue::I32(v) => write!(f, "{}", v),
            SqlMakerBindValue::U64(v) => write!(f, "{}", v),
            SqlMakerBindValue::I64(v) => write!(f, "{}", v),
            SqlMakerBindValue::USIZE(v) => write!(f, "{}", v),
            SqlMakerBindValue::ISIZE(v) => write!(f, "{}", v),
            SqlMakerBindValue::Bool(v) => write!(f, "{}", v),
            SqlMakerBindValue::Str(v) => write!(f, "{}", v),
        }
    }
}

macro_rules! convert_to_sql_maker_bind_value_impl {
    ($($ty1:tt $ty2:tt),+) => ($(
        impl From<$ty2> for $crate::db::query_statement::SqlMakerBindValue {
            fn from(value: $ty2) -> Self {
                $crate::db::query_statement::SqlMakerBindValue::$ty1(value)
            }
        }
    )+)
}

convert_to_sql_maker_bind_value_impl!(U8 u8,I8 i8,U16 u16,I16 i16,U32 u32,I32 i32,U64 u64,I64 i64,USIZE usize,ISIZE isize,Bool bool,Str String);

impl From<&str> for SqlMakerBindValue {
    fn from(value: &str) -> Self {
        SqlMakerBindValue::Str(format!("{}", value))
    }
}

impl From<SqlMakerBindValue> for MySqlArguments {
    fn from(value: SqlMakerBindValue) -> Self {
        let mut args = MySqlArguments::default();
        match value {
            SqlMakerBindValue::U8(v) => args.add(v),
            SqlMakerBindValue::I8(v) => args.add(v),
            SqlMakerBindValue::U16(v) => args.add(v),
            SqlMakerBindValue::I16(v) => args.add(v),
            SqlMakerBindValue::U32(v) => args.add(v),
            SqlMakerBindValue::I32(v) => args.add(v),
            SqlMakerBindValue::U64(v) => args.add(v),
            SqlMakerBindValue::I64(v) => args.add(v),
            SqlMakerBindValue::USIZE(v) => args.add(v as u64),
            SqlMakerBindValue::ISIZE(v) => args.add(v as i64),
            SqlMakerBindValue::Bool(v) => args.add(v),
            SqlMakerBindValue::Str(v) => args.add(v),
        }
        args
    }
}

// use sqlx_core::encode::{Encode,IsNull};
// use sqlx::MySql;
// 批量插入等 绑定值过多时 MySqlArguments::add 太慢  --  其他原因
pub fn convert_list_bind_value_to_args(list: Vec<SqlMakerBindValue>) -> MySqlArguments {
    // let mut has_null_value = false;
    // let mut encode_buf:Vec<u8> = vec![];
    // let mut null_index = vec![];
    // let mut type_list = vec![];
    // let len = list.len();
    // info!("start to convert MySqlArguments. ({})",len);
    // list.into_iter().enumerate().all(|item|{
    //     let is_null = match &item.1 {
    //         SqlMakerBindValue::U8(v) => {
    //             let ty = MySqlArguments::get_mysql_type_info(v);
    //             type_list.push(ty);
    //             <u8 as sqlx::Encode<MySql>>::encode_by_ref(v,&mut encode_buf)
    //         },
    //         SqlMakerBindValue::I8(v) => {
    //              let ty = MySqlArguments::get_mysql_type_info(v);
    //             type_list.push(ty);
    //             <i8 as sqlx::Encode<MySql>>::encode_by_ref(v,&mut encode_buf)
    //         },
    //         SqlMakerBindValue::U16(v) => {
    //              let ty = MySqlArguments::get_mysql_type_info(v);
    //             type_list.push(ty);
    //             <u16 as sqlx::Encode<MySql>>::encode_by_ref(v,&mut encode_buf)
    //         } ,
    //         SqlMakerBindValue::I16(v) => {
    //              let ty = MySqlArguments::get_mysql_type_info(v);
    //             type_list.push(ty);
    //             <i16 as sqlx::Encode<MySql>>::encode_by_ref(v,&mut encode_buf)
    //         },
    //         SqlMakerBindValue::U32(v) => {
    //              let ty = MySqlArguments::get_mysql_type_info(v);
    //             type_list.push(ty);
    //             <u32 as sqlx::Encode<MySql>>::encode_by_ref(v,&mut encode_buf)
    //         },
    //         SqlMakerBindValue::I32(v) => {
    //              let ty = MySqlArguments::get_mysql_type_info(v);
    //             type_list.push(ty);
    //             <i32 as sqlx::Encode<MySql>>::encode_by_ref(v,&mut encode_buf)
    //         },
    //         SqlMakerBindValue::U64(v) => {
    //              let ty = MySqlArguments::get_mysql_type_info(v);
    //             type_list.push(ty);
    //             <u64 as sqlx::Encode<MySql>>::encode_by_ref(v,&mut encode_buf)
    //         },
    //         SqlMakerBindValue::I64(v) => {
    //              let ty = MySqlArguments::get_mysql_type_info(v);
    //             type_list.push(ty);
    //             <i64 as sqlx::Encode<MySql>>::encode_by_ref(v,&mut encode_buf)
    //         },
    //         SqlMakerBindValue::USIZE(v) =>{
    //              let ty = MySqlArguments::get_mysql_type_info(&(*v as i64));
    //             type_list.push(ty);
    //             <u64 as sqlx::Encode<MySql>>::encode_by_ref(&(*v as u64),&mut encode_buf)
    //         } ,
    //         SqlMakerBindValue::ISIZE(v) => {
    //              let ty = MySqlArguments::get_mysql_type_info(&(*v as i64));
    //             type_list.push(ty);
    //             <i64 as sqlx::Encode<MySql>>::encode_by_ref(&(*v as i64),&mut encode_buf)
    //         },
    //         SqlMakerBindValue::Bool(v) => {
    //              let ty = MySqlArguments::get_mysql_type_info(v);
    //             type_list.push(ty);
    //             <bool as sqlx::Encode<MySql>>::encode_by_ref(v,&mut encode_buf)
    //         },
    //         SqlMakerBindValue::Str(v) => {
    //              let ty = MySqlArguments::get_mysql_type_info(v);
    //             type_list.push(ty);
    //             <String as sqlx::Encode<MySql>>::encode_by_ref(v,&mut encode_buf)
    //         },
    //     };
    //     if let IsNull::Yes = is_null {
    //         has_null_value = true;
    //         null_index.push(item.0);
    //     }
    //     true
    // });
    // let mut null_bitmap = vec![0_u8;(len / 8) + 1];
    // if has_null_value {
    //     null_index.iter().all(|index|{
    //         null_bitmap[index / 8] |= (1 << (index % 8)) as u8;
    //         true
    //     });
    // }

    // info!("MySqlArguments Convert Completed! ");
    // MySqlArguments::with(encode_buf,type_list,null_bitmap)
    let mut args = MySqlArguments::default();
    list.into_iter().all(|value| {
        match value {
            SqlMakerBindValue::U8(v) => args.add(v),
            SqlMakerBindValue::I8(v) => args.add(v),
            SqlMakerBindValue::U16(v) => args.add(v),
            SqlMakerBindValue::I16(v) => args.add(v),
            SqlMakerBindValue::U32(v) => args.add(v),
            SqlMakerBindValue::I32(v) => args.add(v),
            SqlMakerBindValue::U64(v) => args.add(v),
            SqlMakerBindValue::I64(v) => args.add(v),
            SqlMakerBindValue::USIZE(v) => args.add(v as u64),
            SqlMakerBindValue::ISIZE(v) => args.add(v as i64),
            SqlMakerBindValue::Bool(v) => args.add(v),
            SqlMakerBindValue::Str(v) => args.add(v),
        }
        true
    });
    args
}


#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum WhereLikeOp {
    Left,
    Right,
    Both,
    None,
}

impl Default for WhereLikeOp {
    fn default() -> Self {
        Self::None
    }
}

#[derive(Debug, Clone, Default,Serialize, Deserialize)]
pub struct SqlMakerRaw {
    pub sql: String,
    pub bind: Option<Vec<SqlMakerBindValue>>,
    pub persistent: bool,
}

impl ToSqlMaker for SqlMakerRaw {
    fn get_sql(&self) -> String {
        self.sql.clone()
    }

    fn get_bind(&self) -> Option<MySqlArguments> {
        if let Some(replace) = self.bind.clone() {
            if replace.is_empty() {
                return None;
            } else {
                return Some(convert_list_bind_value_to_args(replace));
            }
        }
        None
    }

    fn get_persistent(&self) -> bool {
        self.persistent
    }
}

impl SqlMakerRaw {

    pub fn with(sql:String,values:Vec<SqlMakerBindValue>) -> Self{    
        if values.is_empty(){
            return Self { sql, bind: None, persistent: true };
        }
        Self { sql: sql, bind: Some(values), persistent: true }
    }

    pub fn with_sql(sql:String) -> Self{    
        Self{sql, bind: None,persistent: true}
    }

    pub fn set_persistent(&mut self,persistent:bool) -> &Self{
        self.persistent = persistent;
        self
    }

    pub fn set_sql(&mut self,sql:String) -> &Self{
        self.sql = sql;
        self
    }

    pub fn push_value<T:Into<SqlMakerBindValue>>(&mut self,value:T) -> &Self{
        match &mut self.bind {
            Some(v)  => {
                v.push(value.into());
            },
            None => {
                let list = vec![value.into()];
                self.bind = Some(list);
            },
        }
        self
    }

    pub fn is_empty(&self) -> bool {
        self.sql.is_empty()
    }

    pub fn is_bind_empty(&self) -> bool {
        if let Some(x) = &self.bind {
            return x.is_empty();
        }
        return true;
    }

    pub fn get_bind(&self) -> Option<Vec<SqlMakerBindValue>> {
        self.bind.clone()
    }

}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WhereSqlMaker {
    pub inner: SqlMakerRaw,
}

impl Default for WhereSqlMaker {
    fn default() -> Self {
        Self::new("", vec![])
    }
}

impl ToSqlMaker for WhereSqlMaker {
    fn get_sql(&self) -> String {
        self.inner.get_sql()
    }

    fn get_bind(&self) -> Option<MySqlArguments> {
        if let Some(replace) = self.inner.bind.clone() {
            if replace.is_empty() {
                return None;
            } else {
                return Some(convert_list_bind_value_to_args(replace));
            }
        }
        None
    }
}

impl WhereSqlMaker {
    #[inline]
    pub fn with(field: &str) -> Self {
        let sql = field.to_owned();
        Self { inner: SqlMakerRaw::with_sql(sql) }
    }

    #[inline]
    pub fn new(field: &str, replace: Vec<SqlMakerBindValue>) -> Self {
        let sql = field.to_owned();
        if replace.is_empty() {
            Self { inner: SqlMakerRaw::with_sql(sql) }
        } else {
            Self { inner: SqlMakerRaw::with(sql,replace) }            
        }
    }

    #[inline]
    pub fn eq<T: Into<SqlMakerBindValue>>(field: &str, value: T) -> Self {
        let tpl = format!("`{}` = ?", field);
        Self::new(&tpl, vec![value.into()])
    }

    #[inline]
    pub fn not_eq<T: Into<SqlMakerBindValue>>(field: &str, value: T) -> Self {
        let tpl = format!("`{}` <> ?", field);
        Self::new(&tpl, vec![value.into()])
    }

    #[inline]
    pub fn lt<T: Into<SqlMakerBindValue>>(field: &str, value: T) -> Self {
        let tpl = format!("`{}` < ?", field);
        Self::new(&tpl, vec![value.into()])
    }

    #[inline]
    pub fn lte<T: Into<SqlMakerBindValue>>(field: &str, value: T) -> Self {
        let tpl = format!("`{}` <= ?", field);
        Self::new(&tpl, vec![value.into()])
    }

    #[inline]
    pub fn gt<T: Into<SqlMakerBindValue>>(field: &str, value: T) -> Self {
        let tpl = format!("`{}` > ?", field);
        Self::new(&tpl, vec![value.into()])
    }

    #[inline]
    pub fn gte<T: Into<SqlMakerBindValue>>(field: &str, value: T) -> Self {
        let tpl = format!("`{}` >= ?", field);
        Self::new(&tpl, vec![value.into()])
    }

    #[inline]
    pub fn null(field: &str) -> Self {
        let tpl = format!("`{}` IS NULL", field);
        Self::with(&tpl)
    }

    #[inline]
    pub fn not_null(field: &str) -> Self {
        let tpl = format!("`{}` IS NOT NULL", field);
        Self::with(&tpl)
    }

    #[inline]
    pub fn in_set<T: Into<SqlMakerBindValue>>(field: &str, value: Vec<T>) -> Self {
        if value.is_empty() {
            error!("query where in_set value is empty");
            return Self::with("0 = 1");
        }
        let len = value.len();
        let items = std::iter::repeat("?")
            .take(len)
            .collect::<Vec<_>>()
            .join(",");
        let tpl = format!("`{}` IN ({})", &field, items);
        let list_values = value.into_iter().map(|item| item.into()).collect();
        Self::new(&tpl, list_values)
    }

    #[inline]
    pub fn not_in_set<T: Into<SqlMakerBindValue>>(field: &str, value: Vec<T>) -> Self {
        if value.is_empty() {
            error!("query where in_set value is empty");
            return Self::with("0 = 1");
        }
        let len = value.len();
        let items = std::iter::repeat("?")
            .take(len)
            .collect::<Vec<_>>()
            .join(",");
        let tpl = format!("`{}` NOT IN ({})", &field, items);
        let list_values = value.into_iter().map(|item| item.into()).collect();
        Self::new(&tpl, list_values)
    }

    #[inline]
    pub fn like<T: Into<SqlMakerBindValue>>(field: &str, value: T, op: WhereLikeOp) -> Self {
        let left = match op {
            WhereLikeOp::Both => "%",
            WhereLikeOp::Left => "%",
            _ => "",
        };
        let right = match op {
            WhereLikeOp::Both => "%",
            WhereLikeOp::Right => "%",
            _ => "",
        };
        let tpl = format!("`{}` like '{}?{}'", field, left, right);
        Self::new(&tpl, vec![value.into()])
    }

    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }

    pub fn is_bind_empty(&self) -> bool {
        self.inner.is_bind_empty()
    }

    pub fn get_bind(&self) -> Option<Vec<SqlMakerBindValue>> {
        self.inner.get_bind()
    }

    pub fn add(self, other: Self) -> Self {
        if self.is_empty() {
            return other;
        }
        if other.is_empty() {
            return self;
        }
        let sql = format!("{} AND {}", self.get_sql(), other.get_sql());
        let mut replace = vec![];
        if !self.is_bind_empty() {
            replace.extend(self.get_bind().unwrap());
        }
        if !other.is_bind_empty() {
            replace.extend(other.get_bind().unwrap());
        }
        Self::new(&sql, replace)
    }

    pub fn link_and(items: Vec<Self>) -> Self {
        let mut replace = vec![];
        let sql = items
            .into_iter()
            .filter(|item| !item.is_empty())
            .map(|item| {
                if !item.is_bind_empty() {
                    replace.extend(item.get_bind().unwrap());
                }
                item.get_sql()
            })
            .collect::<Vec<_>>()
            .join(" AND ");
        Self::new(&sql, replace)
    }

    pub fn link_or(items: Vec<Self>) -> Self {
        let mut replace = vec![];
        let sql = items
            .into_iter()
            .filter(|item| !item.is_empty())
            .map(|item| {
                if !item.is_bind_empty() {
                    replace.extend(item.get_bind().unwrap());
                }
                format!("({})", item.get_sql())
            })
            .collect::<Vec<_>>()
            .join(" OR ");
        Self::new(&format!("({})", sql), replace)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColumnSqlMaker {
    pub keys: Vec<SqlMakerExpress>,
    pub replace_express: Option<HashMap<String, SqlMakerExpress>>,
    pub values: Option<Vec<SqlMakerBindValue>>,
}

impl Default for ColumnSqlMaker {
    fn default() -> Self {
        Self::new()
    }
}

pub type FieldSqlMaker = SqlMakerRaw;
pub type InsertSqlMaker = SqlMakerRaw;
pub type UpdateSqlMaker = SqlMakerRaw;


impl ColumnSqlMaker {
    pub fn new() -> Self {
        Self {
            keys: vec![],
            replace_express: None,
            values: None,
        }
    }

    pub fn with_keys(cols: Vec<&str>) -> Self {
        let mut res = Self::default();
        let format_keys = cols.into_iter().map(|k| SqlMakerExpress::Str(format!("`{}`", k))).collect();
        res.keys = format_keys;
        res
    }

    pub fn with_literal(col_str:&str) -> Self{
        let mut res = Self::default();
        res.keys = vec![SqlMakerExpress::Literal(col_str.to_owned())];
        res
    }

    pub fn with_literal_keys<T: Into<SqlMakerExpress>>(cols: Vec<T>) -> Self {
        let mut res = Self::default();
        let format_keys = cols.into_iter().map(|k| k.into()).collect();
        res.keys = format_keys;
        res
    }

    pub fn push_values<T: Into<SqlMakerBindValue>>(&mut self, values: Vec<T>) -> &Self {
        match &mut self.values {
            Some(v) => {
                values.into_iter().all(|item| {
                    v.push(item.into());
                    true
                });              
            },
            None => {
                let mut data = vec![];
                values.into_iter().all(|item| {
                    data.push(item.into());
                    true
                }); 
                self.values = Some(data);
            }
        };
        self
    }

    pub fn push_values_convert<F,T>(&mut self,list:Vec<T>,f:F) -> &Self
    where T: Sized,
        F:FnMut(T) -> SqlMakerBindValue,
    {
        let new_data = list.into_iter().map(f).collect::<Vec<_>>();
        match &mut self.values {
            Some(v) => {
                v.extend(new_data);             
            },
            None => {                
                self.values = Some(new_data);
            }
        };
        self
    }

    pub fn push_key_value<T: Into<SqlMakerBindValue>>(&mut self, key: &str, value: T) -> &Self {
        self.keys.push(format!("`{}`",key).into());
        match &mut self.values {
            Some(v) => {
                v.push(value.into());            
            },
            None => {
                let data = vec![value.into()];           
                self.values = Some(data);
            }
        };  
        self
    }

    pub fn push_key_value_literal(&mut self, key: &str, value_literal: &str) -> &Self {
        self.keys.push(format!("`{}`",key).into());
        match &mut self.replace_express {
            Some(v) => {
                v.insert(format!("`{}`", key),SqlMakerExpress::Literal(value_literal.to_owned()));            
            },
            None => {
                let mut data = HashMap::new(); 
                data.insert(format!("`{}`", key),SqlMakerExpress::Literal(value_literal.to_owned()));          
                self.replace_express = Some(data);
            }
        }; 
        self
    }

    pub fn try_to_field_maker(self) -> Result<FieldSqlMaker> {
        if self.values.is_some() {
            warn!("get field from column but values is not none");
        }
        if self.replace_express.is_some() {
            warn!("get field from column but replace_express is not none");
        }
        let sql;
        if self.keys.is_empty() {
            sql = "*".to_owned();
        } else {
            sql = self.keys.into_iter().map(|key|{
                format!("{}",key)
            }).collect::<Vec<_>>().join(",");
        }
        Ok(FieldSqlMaker::with_sql(sql))
    }

    pub fn try_to_insert_maker(self) -> Result<InsertSqlMaker> {
        if self.keys.is_empty() {
            error!("convert column to insert maker.but keys is empty");
            return Err(Error::Common(
                "convert column to insert maker.but keys is empty".to_owned(),
            ));
        } 
        let mut cols = vec![];
        let mut items = vec![];
        let is_replace_express_empty = self.replace_express.is_none();
        let replace = self.replace_express.unwrap_or(HashMap::new());
        for key in self.keys {
            if key.is_literal() {
                warn!("InsertSqlMaker key should be Str Not Literal");
            }
            let col = format!("{}", &key);
            cols.push(col.clone());
            if !is_replace_express_empty && replace.get(&col).is_some() {
                items.push(format!(
                    "{}",
                    replace.get(&col).unwrap()
                ));
            } else {
                items.push("?".to_owned());
            }
        }
        let sql = format!("({}) VALUES({})", cols.join(","), items.join(","));
        Ok(InsertSqlMaker::with(sql, self.values.unwrap_or_default()))
    }

    pub fn try_to_update_maker(self) -> Result<UpdateSqlMaker> {
        if self.keys.is_empty() {
            error!("convert column to update maker.but keys is empty");
            return Err(Error::Common(
                "convert column to update maker.but keys is empty".to_owned(),
            ));
        }
        let is_replace_express_empty = self.replace_express.is_none();
        let replace = self.replace_express.unwrap_or(HashMap::new());
        let mut set_sql_items = vec![];
        for key in self.keys {
            if key.is_literal() {
                warn!("UpdateSqlMaker key should be Str Not Literal");
            }
            let col = format!("{}", &key);
            if !is_replace_express_empty && replace.get(&col).is_some() {
                
                set_sql_items.push(format!(
                    "{} = {}",
                    col,
                    replace.get(&col).unwrap()
                ));
            } else {
                set_sql_items.push(format!("{} = ?", col));
            }
        }
        Ok(UpdateSqlMaker::with(set_sql_items.join(","), self.values.unwrap_or_default()))   
    }

    // pub fn try_to_bulk_insert_maker(self) -> Result<BulkInsertSqlMaker> {
    //     if self.keys.is_empty() {
    //         error!("convert column to bulk insert maker.but keys is empty");
    //         return Err(Error::Common(
    //             "convert column to bulk insert maker.but keys is empty".to_owned(),
    //         ));
    //     }

    //     if self.values.is_none() {
    //         error!("convert column to bulk insert maker.but values is empty");
    //         return Err(Error::Common(
    //             "convert column to bulk insert maker.but values is empty".to_owned(),
    //         ));
    //     }
    //     if self.replace_express.is_some() {
    //         warn!("BulkInsertSqlMaker replace_express should be Empty. but now has some data");
    //     }
 
    //     let cols = self.keys.into_iter().map(|key|{
    //         format!("{}",key)
    //     }).collect::<Vec<_>>().join(",");

    //     let items = self
    //         .values
    //         .unwrap()
    //         .into_iter()
    //         .map(|item| format!("({})", item))
    //         .collect::<Vec<_>>()
    //         .join(",");
    //     let sql = format!("({}) VALUES {}", cols, items);
    //     let mut maker = BulkInsertSqlMaker::with_sql(sql);
    //     maker.set_persistent(false);
    //     Ok(maker)
    // }
}


#[derive(Debug, Clone, Serialize, Deserialize,Default)]
pub struct BulkInsertSqlMaker {
    pub keys: Vec<String>,
    pub value_tpl: String,
    pub items_num: i32,
    pub values: Vec<SqlMakerBindValue>,
}

impl BulkInsertSqlMaker {
    pub fn with(cols: Vec<&str>) -> Self {
        let len = cols.len();
        let tpl = iter::repeat("?").take(len).collect::<Vec<_>>().join(",");
        Self::with_value_tpl(cols,tpl.as_str())
    }

    pub fn with_value_tpl(cols: Vec<&str>,tpl:&str) -> Self {
        let mut res = Self::default();
        let format_keys = cols.into_iter().map(|k| format!("`{}`", k)).collect();
        res.keys = format_keys;
        res.value_tpl = format!("({})",tpl);
        res.items_num = 0;
        res
    }

    pub fn push_values_convert<F,T>(&mut self,list:Vec<T>,f:F) -> &Self
    where T: Sized,
        F:FnMut(T) -> Vec<SqlMakerBindValue>,
    {
        let len = list.len() as i32;
        if len > 0 {
            self.items_num = self.items_num + len;
            list.into_iter().map(f).all(|list_data|{
                self.values.extend(list_data);
                true
            });
        }
        self
    }

    pub fn try_to_raw_maker(self) -> Result<SqlMakerRaw>{
        if self.keys.is_empty() {
            error!("try to make bulk insert sql. but keys is empty");
            return Err(Error::Common(
                "try to make bulk insert sql. but keys is empty".to_owned(),
            ));
        } 
        if self.items_num < 1 {
            error!("try to make bulk insert sql. but data is empty");
            return Err(Error::Common(
                "try to make bulk insert sql. but data is empty".to_owned(),
            ));
        }
        let cols = self.keys.into_iter().map(|key|{
            format!("{}",key)
        }).collect::<Vec<_>>().join(",");
        let value_tpl = iter::repeat(self.value_tpl).take(self.items_num as usize).collect::<Vec<_>>().join(",");
        let sql_tpl = format!("({}) VALUES {}",cols,value_tpl);
        let mut maker = SqlMakerRaw::with(sql_tpl,self.values);
        //maker.set_persistent(false);
        Ok(maker)
    }

}

pub mod prelude {
    pub use super::{
        BulkInsertSqlMaker, ColumnSqlMaker, FieldSqlMaker, InsertSqlMaker, SqlMakerBindValue,
        SqlMakerExpress, SqlMakerRaw, ToSqlMaker, UpdateSqlMaker, WhereLikeOp, WhereSqlMaker,
    };
}
